package com.gopay.common.util.xml.tools.impl;

import java.io.File;
import java.io.FilenameFilter;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.common.util.xml.tools.XmlToolsService;
import com.gopay.common.util.xml.utils.Assert0;
import com.gopay.common.util.xml.utils.XmlBeansUtils;
import com.gopay.common.util.xml.xmlutils.MessagesBuilder;
import com.gopay.common.util.xml.xmlutils.message.Message;
import com.gopay.common.util.xml.xmlutils.read.XmlProFileReader;
import com.gopay.common.util.xml.xmlutils.read.impl.XmlProFileReaderImpl;
import com.gopay.common.util.xml.xmlutils.tools.XmlUtilTools;

/**
 * 
 * @XmlMessageServiceImpl.java
 * @author liujy
 * @2013-4-19 下午2:51:47  www.gopay.com.cn Inc.All rights reserved.
 */
public class XmlToolsServiceImpl implements XmlToolsService{
	
	private final Logger logger = LoggerFactory.getLogger(XmlToolsServiceImpl.class);

	/** 默认配置文件路径 */
	private final String DEFAULT_RES_PRO_FILE_DIR = "message/response";
	private final String DEFAULT_REQ_PRO_FILE_DIR = "message/request";

	/** message对象集 */
	private Map<String, Message> messages;
	/** 配置文件目录 */
	private List<String> proFileDirs;
	/** 配置文件 */
	private List<String> proFiles;

	/**
	 * obj解析为xml
	 * @param msgType
	 * @param data
	 * @return
	 */
	@Override
    public String j2xml(Object data){
		return j2xml(data, "UTF-8");
	}
	
	/**
	 * obj解析为xml
	 * @param msgType
	 * @param data
	 * @return
	 */
	@Override
    public String j2xml(Object data, String encoding){
		Assert0.notNull(data, "The data must not be null");
		return j2xml(getMsgType(data), data);
	}
	
	/**
	 * obj解析为xml
	 * @param msgType
	 * @param data
	 * @return
	 */
	@Override
    public String j2xml(String msgType, Object data){
		return j2xml(msgType, data, "UTF-8");
	}
	
	/**
	 * obj解析为xml
	 * @param msgType
	 * @param data
	 * @return
	 */
	@Override
    public String j2xml(String msgType, Object data, String encoding){
		Assert0.notEmpty4String(msgType, "msgType is invalid: " + msgType);
		
		Message message = getMessage(msgType);
		
		Assert0.notNull(message, "The message must not be null, msgType： " + msgType);
		
		return XmlUtilTools.builderXml(message, data, encoding);
	}
	
	/**
	 * xml解析为obj
	 * @param xml
	 * @return
	 * @throws Exception 
	 */
	@Override
    public Object xml2j(String xml){
		
		Assert0.notNull(xml, "The xml must not be null");
		
		int index = xml.indexOf("<msgType>");
		int last = xml.indexOf("</msgType>");
		if((index == -1 || last == -1)
				|| last < index){
			throw new IllegalArgumentException("报文格式错, request: " + xml);
		}
		
		String msgType = xml.substring(index + 9, last);
		
		try {
		    return xml2j(msgType, xml);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
	}
	
	/**
	 * xml解析为obj
	 * @param msgType
	 * @param data
	 * @return
	 * @throws Exception 
	 */
	@Override
    public Object xml2j(String msgType, String xml){
		
		Assert0.notEmpty4String(msgType, "msgType is invalid: " + msgType);
		
		Message message = getMessage(msgType);
		
		Assert0.notNull(message, "The message must not be null, msgType： " + msgType);
		
		try {
            return XmlUtilTools.builderObj(message, xml);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
	}
	
	

	/**
	 * 
	 * @param msgType
	 * @param ioFlag
	 * @return
	 */
	private Message getMessage(String msgType) {
		if (messages == null) {
			synchronized (XmlToolsServiceImpl.class) {
				if(messages == null){
					buildMessages();
				}
			}
		}
		return messages.get(msgType);
	}

	/**
	 * 
	 * @throws Exception
	 */
	private void buildMessages(){
		try {
			XmlProFileReader define = new XmlProFileReaderImpl();
			Document[] documents = define.read(getProFiles());
			Document document = define.merge(documents);
			this.messages = MessagesBuilder.getInstance().builder(document);
		} catch (Throwable e) {
			logger.error("init messages error: ", e);
		}
	}

	/**
	 * 
	 * @return
	 */
	private List<String> getProFiles() throws Exception {
		
		proFiles = proFiles == null ? new ArrayList<String>() : proFiles;
		proFileDirs = proFileDirs == null ? new ArrayList<String>() : proFileDirs;
		
		if (proFiles.isEmpty() && proFileDirs.isEmpty()) {
			logger.info("DEFAULT_REQ_PRO_FILE_DIR: " + DEFAULT_REQ_PRO_FILE_DIR 
					+ "|DEFAULT_RES_PRO_FILE_DIR: " + DEFAULT_RES_PRO_FILE_DIR);
			
			proFileDirs.add(DEFAULT_RES_PRO_FILE_DIR);
			proFileDirs.add(DEFAULT_REQ_PRO_FILE_DIR);
		}

		List<String> files = new ArrayList<String>(proFiles);
		String path = getClass().getResource("/").toString();
		
		for(String proFileDir : proFileDirs){
			File dir = new File(new URI(path + proFileDir));
			String[] names = dir.list(new FilenameFilter() {
				@Override
                public boolean accept(File dir, String name) {
					if (name.toLowerCase().endsWith(".xml")) {
						return true;
					}
					return false;
				}
			});
			if(names == null || names.length == 0){
				continue;
			}
			proFileDir = proFileDir.concat("/");
			for (String name : names) {
				StringBuilder temp = new StringBuilder(proFileDir);
				files.add(temp.append(name).toString());
			}
		}
		return files;
	}
	
	/**
	 * msgType
	 * 
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private String getMsgType(Object data) {
		Object value;
		try {
			value = XmlBeansUtils.getPropertyObject(data, "msgType");
			return value == null ? null : value.toString().trim();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public void setProFileDirs(List<String> proFileDirs) {
		this.proFileDirs = proFileDirs;
	}

	public void setProFiles(List<String> proFiles) {
		this.proFiles = proFiles;
	}
}
